package main

import "fmt"

// 注意区分clouser()3与clouser()4
func main() {
	//clouser1() //闭包未修改局部变量值,捕获列表中捕获的变量直接赋值，所有funcval中的变量一致
	//clouser2() // 闭包修改局部变量值，局部变量逃逸到堆上，每个funcval单独在堆上维护自己的捕获列表,不同funcval中捕获的变量是单独维护的，相互隔离
	//clouser3() // 闭包函数捕获的局部变量在闭包函数外部修改，局部变量逃逸到堆上，捕获列表中的捕获变量存的是局部变量堆中的地址
	clouser4() // 闭包外修改局部变量，函数返回的funcval不会随调用更改
}

// 被捕获变量除了初始化赋值，在任何地方都没有被修改过，所以直接拷贝值到捕获列表就可以了
func create() func() int {
	c := 2 // 局部变量被捕获
	return func() int {
		return c
	}
}
func clouser1() {
	f1 := create()
	f2 := create()
	fmt.Printf("f1.addr:%p\n", f1)
	fmt.Printf("f2.addr:%p\n", f2)
	f1()
	f1()
	fmt.Printf("f1.val:%v,f2.val:%v\n", f1(), f2())
}

// 闭包中修改局部变量，每个funcval的捕获列表(代码段+变量)中的变量由自己保存，不同的funcval间是隔离的
func create2() func() int {
	c := 2
	return func() int {
		c++
		return c
	}
}
func clouser2() {
	f1 := create2()
	f2 := create2()
	fmt.Printf("f1.addr:%p val %v\n", f1, f1())
	fmt.Printf("f2.addr:%p val %v\n", f2, f2())
	f1() // 3
	f1() // 4
	fmt.Printf("f1.val:%v,f2.val:%v\n", f1(), f2())
	//output 5 3
}

// 闭包外修改局部变量，闭包中并未修改，即返回的funcval不会随调用而改变c的值。
func create4() func() int {
	c := 2
	c++
	return func() int {
		return c
	}
}
func clouser4() {
	f1 := create4()
	f2 := create4()
	fmt.Printf("f1.addr:%p\n", f1)
	fmt.Printf("f2.addr:%p\n", f2)
	f1() // 2
	f1() // 2
	fmt.Printf("f1.val:%v,f2.val:%v\n", f1(), f2())
	//output 2 3
}

func create3() (fs [2]func()) {
	for i := 0; i < 2; i++ {
		fs[i] = func() { //闭包捕获的局部变量i 逃逸到堆上，因此栈上存的是i的地址，每个func value 中存的也是 i 的地址
			fmt.Println("after", i)
		}
	}
	return
}

func clouser3() {
	fs := create3()
	for i := 0; i < len(fs); i++ {
		fs[i]()
	}
}
